#include "DbcParser.h"
#include "canframe.h"
#include "zdbc.h"

#include <QDebug>
#include <stdio.h>
#include <string.h>

DbcParser::DbcParser()
    : itsFilePath(), itsMessages(), itsDbcHandler(0), itsMsgMap()
{
    itsDbcHandler = ZDBC_Init();
}

DbcParser::~DbcParser()
{
    ZDBC_Release(itsDbcHandler);
}

bool DbcParser::load(const QString& path)
{
    FileInfo fileinfo;
    strcpy_s(fileinfo.strFilePath, _MAX_FILE_PATH_, path.toStdString().c_str());
    fileinfo.merge = false;//清除记录
    if (!ZDBC_LoadFile(itsDbcHandler, &fileinfo))
    {
        qWarning() << "加载文件失败!";
        return false;
    }

    if (0 == ZDBC_GetMessageCount(itsDbcHandler))
    {
        qWarning() << "文件中不含有消息!";
        return false;
    }
    ReadAllMessage();

    for(const auto& msg : itsMessages)
    {
        for(const auto& sig : msg.second.vSignals)
        {
            if(isEmptySiganl(sig))
            {
                break;
            }
            itsMsgMap[std::string(sig.strName)] = msg.second.nID;
        }
    }

    return true;
}

void DbcParser::ReadAllMessage()
{
    DBCMessage msg;
    if (ZDBC_GetFirstMessage(itsDbcHandler, &msg))
    {
        itsMessages.emplace(msg.nID, msg);
        while(ZDBC_GetNextMessage(itsDbcHandler, &msg))
        {
            itsMessages.emplace(msg.nID, msg);
        }
    }
}

void DbcParser::printMessages()
{
    // for(const auto& msg : itsMessages)
    // {
    //     printf("Message : [id:%x  name:%s  cycleTime:%f]\n", msg.first, msg.second.strName, msg.second.nCycleTime);
    //     for(const auto& sig : msg.second.vSignals)
    //     {
    //         if(isEmptySiganl(sig))
    //         {
    //             break;
    //         }
    //         printf("\tSignal : [name:%s]\n", sig.strName);
    //     }
    // }
}

bool DbcParser::isEmptySiganl(const DBCSignal& sig)
{
    return sig.nLen == 0;
}

void DbcParser::printMsg(const DBCMessage* dbcMsg)
{
    if(dbcMsg)
    {
        printf("Message : [name:%s  cycleTime:%f]\n", dbcMsg->strName, dbcMsg->nCycleTime);
        for(int i = 0; i < _DBC_SIGNAL_MAX_COUNT_; i++)
        {
            const DBCSignal& sig = dbcMsg->vSignals[i];
//            if(isEmptySiganl(sig))
            {
                printf("\tnsigName:%s nStartBit:%d, nLen:%d, nFactor:%lf, nOffset:%lf, nRawValue:0x%llx, encode as:%s\n", sig.strName, sig.nStartBit, sig.nLen, sig.nFactor, sig.nOffset, sig.nRawValue, (sig.is_motorola?"motorola":"intel"));
            }
        }
    }
}

DBCSignal* DbcParser::findSignalWithMessage(DBCMessage& dbcMsg, const std::string& sigName)
{
    for(int i = 0; i < _DBC_SIGNAL_MAX_COUNT_; i++)
    {
        if(strcmp(dbcMsg.vSignals[i].strName, sigName.c_str()) == 0)
        {
            return &dbcMsg.vSignals[i];
        }
    }
    return nullptr;
}

void DbcParser::buildDbcMsg(DBCMessage& dbcMsg, const std::string& sigName, const std::string& sigValue)
{
    DBCSignal* sig = findSignalWithMessage(dbcMsg, sigName);
    if(sig)
    {
        double value = std::stod(sigValue);
//        sig->nRawValue = (value - sig->nOffset)/sig->nFactor;
        sig->nRawValue = ZDBC_CalcRawValue(sig, &value);
    }
}


bool DbcParser::updateDbcMsg(const CanId& msgId, const std::string& sigName, double sigValue)
{
    bool ret = false;
    do
    {
        auto msgIt = itsMessages.find(msgId);
        if(msgIt == itsMessages.end())
        {
            break;
        }

        DBCSignal* sig = findSignalWithMessage(msgIt->second, sigName);
        if(!sig)
        {
            break;
        }
        sig->nRawValue = ZDBC_CalcRawValue(sig, &sigValue);
        ret = true;

    } while(false);

    return ret;
}

bool DbcParser::encodeAsCanMessage(DBCMessage* msg, std::vector<uint8_t>& output)
{
    uint32_t LEN = sizeof(can_frame);
    output.resize(msg->nSize);
    can_frame obj;
    std::fill_n(output.begin(), 0, msg->nSize);
    auto res = ZDBC_Encode(itsDbcHandler, &obj, &LEN, msg);
    std::copy(obj.data, obj.data+msg->nSize, output.begin());
    return res;
}

bool DbcParser::encodeAsCanFdMessage(DBCMessage* msg, std::vector<uint8_t>& output)
{
    uint32_t LEN = sizeof(can_frame);
    constexpr auto CANFD_SIZE = 64;
    output.resize(CANFD_SIZE);
    canfd_frame obj;
    std::fill_n(output.begin(), 0, CANFD_SIZE);
    auto res = ZDBC_Encode(itsDbcHandler, &obj, &LEN, msg);
    std::copy(obj.data, obj.data+CANFD_SIZE, output.begin());
    return res;
}

bool DbcParser::encodeCanMsg(DBCMessage* msg, void* obj)
{
    return ZDBC_Decode(itsDbcHandler, msg, obj, 1);
}

int DbcParser::getMsgIdBySigName(const char* sigName)
{
    std::string key(sigName);
    if (itsMsgMap.find(key) != itsMsgMap.end())
    {
        return itsMsgMap[key];
    }
    else
    {
        return -1;
    }
}

void DbcParser::foreachDbcMessageMap(std::function<void(DBCMessage* msg)> cb)
{
    for(const auto& dbcMsg : itsMessages)
    {
        cb(const_cast<DBCMessage*>(&dbcMsg.second));
    }
}

